﻿using Grpc.Core;
using MX.Core.Extensions;
using MX.Core.Log;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UserCenter.Console.Sdk.Core;
using UserCenter.Console.Sdk.Models; 
using static UserCenter.Grpc.Sdk.ConsoleApi;
using GrpcErrorMessage =MX.Proto.ErrorMessage;


namespace UserCenter.Console.Sdk.Core
{
    public abstract class BaseSdk
    {
        const int timeoutSenconds = 30;

        protected ILogger logger = Logger.GetLogger(nameof(MemberSdk));

        string host;
        int port;

        long merchantId;
        string signKey;

        Channel channel;
        protected ConsoleApiClient client;


        /// <summary>
        /// 实例化
        /// </summary>
        /// <param name="merchantId">商户号</param>
        /// <param name="signKey">签名KEY</param>
        public BaseSdk(long merchantId, string signKey, string host, int port)
        {
            this.merchantId = merchantId;
            this.signKey = signKey;
            this.host = host;
            this.port = port;
            channel = new Channel(host, port, ChannelCredentials.Insecure);
            client = new ConsoleApiClient(channel);
        }

        Metadata GetHeaders()
        {
            Metadata headerMeta = new Metadata();
            var timestamp = DateTime.Now.ToTimestamp().ToString();
            headerMeta.Add(new Metadata.Entry("Timestamp", timestamp));
            headerMeta.Add(new Metadata.Entry("MerchantId", merchantId.ToString()));
            string signValue = $"{timestamp}{signKey}".MD5().MD5();
            headerMeta.Add(new Metadata.Entry("Sign", signValue));
            return headerMeta;
        }

        /// <summary>
        /// GRPC 请求
        /// </summary>
        /// <typeparam name="Q"></typeparam>
        /// <typeparam name="R"></typeparam>
        /// <param name="requestHander"></param>
        /// <param name="request"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        async protected Task<GrpcRequestResult<R>> RequestAsync<Q, R>(RequestHander<Q, R> requestHander, Q request, object headers = null)
        {
            var grpcResult = new GrpcRequestResult<R>();

            if (channel.State == ChannelState.Connecting)
            {
                for (int i = 0; i < timeoutSenconds / 10 / 2; i += 10)
                {
                    if (channel.State != ChannelState.Connecting)
                    {
                        break;
                    }
                    await Task.Delay(10);
                }
            }
            if (channel.State == ChannelState.TransientFailure)
            {
                for (int i = 0; i < timeoutSenconds / 10 / 2; i += 10)
                {
                    if (channel.State != ChannelState.TransientFailure)
                    {
                        break;
                    }
                    await Task.Delay(10);
                }
            }
            if (channel.State == ChannelState.Shutdown)
            {
                for (int i = 0; i < 3; i++)
                {
                    await channel.ConnectAsync(DateTime.Now.AddSeconds(timeoutSenconds / 3));
                }
            }
            if (channel.State != ChannelState.Ready && channel.State != ChannelState.Idle)
            {
                grpcResult.Success = false;
                grpcResult.Message = "无法连接到服务器,请检查网络并重试";
            }
            else
            {
                Metadata headerMeta = GetHeaders();
                var outMeta = Utils.Object2Meta(headers);
                if (outMeta != null)
                {
                    foreach (var item in outMeta)
                    {
                        var orgiEntry = headerMeta.SingleOrDefault(e => e.Key.Equals(item.Key));
                        if (orgiEntry != null)
                        {
                            headerMeta.Remove(orgiEntry);
                        }
                        headerMeta.Add(item.Key, item.ValueBytes);
                    }
                }
                try
                {
                    var response = await requestHander(request, headerMeta);
                    grpcResult.Success = true;
                    grpcResult.Response = response;
                }
                catch (RpcException ex)
                {
                    logger.Debug(ex.ToString());
                    var metadata = ex.Trailers;
                    var errEntry = metadata.Where(entry => entry.Key.Equals("error", StringComparison.CurrentCultureIgnoreCase)).Take(1).SingleOrDefault();
                    if (errEntry != null)
                    {
                        var error = GrpcErrorMessage.Parser.ParseFrom(Convert.FromBase64String(errEntry.Value));
                        grpcResult.Success = false;
                        grpcResult.Message = $"服务端返回\n{error.Message}\n{error.Code}";
                        grpcResult.Code = error.Code.ToString();
                        logger.Debug(error.ToString());
                    }
                    else
                    {
                        grpcResult.Success = false;
                        grpcResult.Message = $"本地错误\n{ex.Message}";
                    }
                }
                catch (Exception ex)
                {
                    logger.Debug(ex.ToString());
                    grpcResult.Success = false;
                    grpcResult.Message = $"本地错误\n{ex.Message}";
                }
            }

            return grpcResult;
        }
    }
}
